using FlyIL.Expression;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using FlyIL.Advance;
using static FlyIL.AssemblerRegisters;
using static FlyIL.OperandMaker;

namespace FlyIL.Trace.Tests
{




    [TestClass()]
    public class 追踪_宽度不一致
    {
        [TestMethod()]
        public void tetet11()
        {
            //3037AB2 push   ebx
            //3037AB3 movzx  ebx, ax
            //3037AB6 movsx  ebx, sp
            //      - xchg dh,dl



        }

        [TestMethod()]
        public void tetet1111111111111()
        {


            var vcontext = new Context(true);
            /// 这里宽度不一致，虽然本质上可以化简，
            /// 但是因为 不能追踪，所以不做处理 
            vcontext = new Context(true, 0);

            vcontext.Make().push(_word_[R6D]);
            vcontext.Make().xor(R1D, R1D);

            vcontext.Make().mov(R1W, 0x7788);
            vcontext.Make().pop(R1W);


            vcontext.Make().mov(R1L, _byte_[R7D + R1D]);


            var rax = _regs_[R1D];

            var exp = vcontext.TraceStrict(vcontext.Last.Previous, ref rax);
            Assert.IsFalse(exp.Calculable);

        }

        /// <summary>
        /// 宽度不一致  或 偏移不一致的情况 
        /// </summary>

        [TestMethod()]
        public void 追踪到部分寄存器()
        {


            var vcontext = new Context(true);
            /// 这里宽度不一致，虽然本质上可以化简，
            /// 但是因为 不能追踪，所以不做处理 
            vcontext = new Context(true, 0);

            vcontext.Make().mov(R1D, (uint)0x1234_5678);

            vcontext.Make().mov(R0W, R1W);


            var exp = vcontext.TraceStrict(vcontext.Last, ref vcontext.Last.O1);
            Assert.AreEqual(exp.Result, (ulong)0x5678);

        }



        [TestMethod()]
        public void 追踪到部分寄存器111()
        {

            {
                RegCodeLocalism.Current = PlatLocalism.Arm;

                var vcontext = new Context(true);

                vcontext.Make().mov(R2L, 123);
                vcontext.Make().movzx(R1D, R2L);    // r1h = 0  
                vcontext.Make().shl(R1H, 2);
                var exp = vcontext.TraceStrict(vcontext.Last, ref vcontext.Last.O1);
                Assert.AreEqual(exp.Result, (ulong)0);

            }


            {
                RegCodeLocalism.Current = PlatLocalism.Arm;

                var vcontext = new Context(true);

                vcontext.Make().mov(R2L, 123);
                vcontext.Make().movzx(R1D, R2L);    // r1l = r2l 
                vcontext.Make().shl(R1L, 2);
                var exp = vcontext.TraceStrict(vcontext.Last, ref vcontext.Last.O1);
                Assert.IsTrue(exp.Calculable);

            }

            {
                var vcontext = new Context(true);

                vcontext.Make().mov(R0H, 123);
                vcontext.Make().movzx(R0D, R0W);    //无影响
                vcontext.Make().mov(R1L, R0H);
                var exp = vcontext.TraceStrict(vcontext.Last, ref vcontext.Last.O1);
                Assert.AreEqual(exp.Result, (ulong)123);

            }


            {
                var vcontext = new Context(true);

                /// r0l =  r0h  
                vcontext.Make().movzx(R0W, R0H);
                vcontext.Make().mov(R1L, R0L);

                var exp = vcontext.TraceStrict(vcontext.Last, ref vcontext.Last.O1);
                Assert.AreEqual(exp.FinalLeft<Operand>(), _regs_[R0H]);
            }

            {

                var vcontext = new Context(true);

                /// 此时 R0H 是0， 可以 放弃追踪了 
                vcontext.Make().movzx(R0W, R0L);
                vcontext.Make().mov(R1L, R0H);
                var exp = vcontext.TraceStrict(vcontext.Last, ref vcontext.Last.O1);
                Assert.AreEqual(exp.Result, (ulong)0);

            }



        }






        /// <summary>
        /// 宽度不一致  或 偏移不一致的情况 
        /// </summary>

        [TestMethod()]
        public void TraceExpTest()
        {

            Assert.ThrowsException<Exception>(() =>
            {


                var vcontext = new Context(true);
                /// 这里宽度不一致，虽然本质上可以化简，
                /// 但是因为 不能追踪，所以不做处理 
                vcontext = new Context(true, 0);
                vcontext.Make().push((ulong)1111);              // 保留
                vcontext.Make().xor(_byte_[Rsp], 0x45);

                vcontext.SimplifyOnce();
                vcontext.ClearNop();
                Assert.AreEqual(vcontext.Codes.Count, 2);
            });

        }


        /// <summary>
        ///  al + ah => ax 
        /// </summary>
        [TestMethod()]
        public void 寄存器部分赋值的情况()
        {


            var vcontext = new Context(true);

            {
                vcontext = new Context(true, 0);

                vcontext.Make().mov(R1D, 0);
                vcontext.Make().mov(R1L, 0x46);
                vcontext.Make().mov(R1H, 0);

                vcontext.Make().mov(R2D, R1D);


                var exp = vcontext.TraceStrict(vcontext.Last, ref vcontext.Last.O1);
                Assert.AreEqual(exp.Result, (ulong)0x46);
            }


            {
                vcontext = new Context(true, 0);

                vcontext.Make().mov(R1L, 0x46);
                vcontext.Make().mov(R1L, 0x23);

                vcontext.Make().mov(R2D, R1D);


                var exp = vcontext.TraceStrict(vcontext.Last, ref vcontext.Last.O1);
                Assert.AreEqual(exp.CalcDepth, 1);
            }



            {

                vcontext = new Context(true, 0);

                vcontext.Make().mov(R0D, 0x1234_0000);
                vcontext.Make().mov(R0W, 0x46);

                vcontext.Make().mov(R2D, R0D);


                var exp = vcontext.TraceStrict(vcontext.Last, ref vcontext.Last.O1);
                Assert.AreEqual(exp.Result, (ulong)0x1234_0046);
            }



        }

        /// <summary>
        ///  未对齐 ???
        /// </summary>

        [TestMethod()]
        public void NotIITest()
        {

            var vcontext = new Context(true, 0);
            vcontext.Make().mov(R1D, 0x100);
            vcontext.Make().mov(R1L, 0x11);

            vcontext.Make().mov(R3D, R1D);


            var exp = vcontext.TraceStrict(vcontext.Last, ref vcontext.Last.O1);

            Assert.AreNotEqual(exp, null);

            Assert.IsTrue(exp.Calculable);

            Assert.AreEqual(exp.Result, (ulong)0x111);


        }

        [TestMethod()]
        public void 不对称压栈()
        {



            Context vcontext;
            //---  不对称 压栈 和弹栈    
            vcontext = new Context(false);
            vcontext.Make().push(R1D);
            vcontext.Make().pop(R6W);              // 化简为 mov (r6w , r1w) , 而不是将此代码直接 nop 掉 

            var node = vcontext.TraceStrict(vcontext.Codes.Last, ref vcontext.Codes.Last.O1);
            node.Simplify();

            Assert.AreEqual(node.FinalLeft<Operand>(), OperandMaker._regs_[R1W]);

        }

    }

}